package com.cjd.common.utils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * @author chenjidong
 * @email 374122600@qq.com
 * created 2020/5/29/0029
 * description 泛型参数工具类
 */
public class GenericParamUtil {

    /**
     * 获取接口泛型参数
     *
     * @param object 接口
     * @param index  参数下标 0 左边第一个
     * @return 运行时类型
     */
    public static Class<?> getInterfaceT(Object object, int index) {
        Type[] types = object.getClass().getGenericInterfaces();

        ParameterizedType parameterizedType = (ParameterizedType) types[index];
        Type type = parameterizedType.getActualTypeArguments()[index];
        return checkType(type, index);
    }

    /**
     * 获取类泛型参数
     *
     * @param object 接口
     * @param index  参数下标 0 左边第一个
     * @return 运行时类型
     */
    public static Class<?> getClassT(Object object, int index) {
        Type type = object.getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Type type1 = parameterizedType.getActualTypeArguments()[index];
            return checkType(type1, index);
        } else {
            String className = type == null ? "null" : type.getClass().getName();
            throw new IllegalArgumentException("Expected a Class, ParameterizedType"
                    + ", but <" + type + "> is of type " + className);
        }
    }

    /**
     * 检查 type 是否 泛型参数 (非泛型类 或 没有继承泛型接口 会抛出异常)
     *
     * @param type  clazz
     * @param index 默认读取第一个 泛型参数
     * @return 接口或class 上的泛型T
     */
    public static Class<?> checkType(Type type, int index) {
        if (type instanceof Class<?>) {
            return (Class<?>) type;
        } else if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Type type1 = parameterizedType.getActualTypeArguments()[index];
            return checkType(type1, index);
        } else {
            String className = type == null ? "null" : type.getClass().getName();
            throw new IllegalArgumentException("Expected a Class, ParameterizedType"
                    + ", but <" + type + "> is of type " + className);
        }
    }
}
